package user

import (
	"context"
	"strconv"
	"strings"
	"time"

	"mall/common/globalkey"
	"mall/common/jwt"
	"mall/common/modelx"
	"mall/common/utils/pointy"
	"mall/service/backend/api/internal/svc"
	"mall/service/backend/api/internal/types"
	"mall/service/backend/common/enum/common"
	"mall/service/backend/common/enum/errorcode"
	"mall/service/backend/common/errorx"
	"mall/service/backend/rpc/backendclient"

	"github.com/zeromicro/go-zero/core/logx"
)

type LoginLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic {
	return &LoginLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *LoginLogic) Login(req *types.LoginReq) (resp *types.LoginResp, err error) {
	if req.CaptchaId != nil && req.Captcha != nil {
		if ok := l.svcCtx.Captcha.Verify(*req.CaptchaId, *req.Captcha, true); !ok {
			return nil, errorx.NewCodeError(errorcode.InvalidArgument,
				l.svcCtx.Trans.Trans(l.ctx, "login.wrongCaptcha"))
		}
	}

	var account *string
	if req.Type != nil && len(strings.TrimSpace(*req.Type)) > 0 {
		switch strings.TrimSpace(*req.Type) {
		case globalkey.UserAuthTypeAccount:
			account = req.Username
		default:
			account = req.Username
		}
	}

	res, err := l.svcCtx.BackendRpc.Login(l.ctx, &backendclient.LoginReq{
		Account:   account,
		Password:  req.Password,
		Type:      req.Type,
		WithRoles: pointy.GetPointer(uint32(1)),
	})
	if err != nil {
		return
	}

	token, err := jwt.NewJwtToken(
		l.svcCtx.Config.Auth.AccessSecret,
		time.Now().Unix(),
		l.svcCtx.Config.Auth.AccessExpire,
		jwt.WithOption("userId", res.Id),
		jwt.WithOption("roles", strings.Join(res.RoleCodes, ",")),
	)
	if err != nil {
		return
	}

	// add token into database
	expiredAt := modelx.FormatTime(
		time.Now().Add(time.Second*time.Duration(l.svcCtx.Config.Auth.AccessExpire)),
		"",
	)
	_, err = l.svcCtx.BackendRpc.CreateToken(l.ctx, &backendclient.TokenInfo{
		Uuid:      pointy.GetPointer(strconv.FormatInt(int64(*res.Id), 10)),
		Token:     pointy.GetPointer(token),
		Source:    pointy.GetPointer("system"),
		Status:    pointy.GetPointer(uint32(globalkey.StatusEnabled)),
		ExpiredAt: pointy.GetPointer(expiredAt),
	})
	if err != nil {
		return
	}

	var access string = "guest" // "admin" | "user" | "guest"
	if len(res.RoleIds) > 0 {
		access = "user"
		for _, v := range res.RoleIds {
			if v <= common.DefaultAdminRoleId { // 是默认的系统管理员或超级管理员角色
				access = "admin"
				break
			}
		}
	}

	return &types.LoginResp{
		BaseDataInfo: types.BaseDataInfo{
			Success: true,
			Msg:     l.svcCtx.Trans.Trans(l.ctx, "login.loginSuccessTitle"),
		},
		Data: types.LoginInfo{
			Status: "ok", // "error"
			Type:   req.Type,
			Access: access,
			Token:  token,
		},
	}, nil
}
